package neo.aoi;

import artofillusion.math.Vec3;

/**
 * This class defines a plane in the 3D space. Some utilities for a plane are
 * given.
 * 
 * @author Carlos Martinez
 */
public class Plane {
	private Vec3 _a;

	private Vec3 _n;

	private double _d;

	/**
	 * Creates a new <code>Plane</code> which is common to the 3 given points.
	 * The 3 points must not live in the same line, otherwise, unexpected
	 * results may occur.
	 * 
	 * @param a
	 *            First point
	 * @param b
	 *            Second point
	 * @param c
	 *            Third point
	 */
	public Plane(Vec3 a, Vec3 b, Vec3 c) {
		this._a = a;

		_n = b.minus(_a).cross(c.minus(_a));
		_n.normalize();
		_d = _a.dot(_n);
	}

	/**
	 * Checks if the line defined by points p0 and p1 intersects with this
	 * plane. Note that the intersection does not necesarily occur between p0
	 * and p1
	 * 
	 * @param p0
	 *            one point on the line
	 * @param p1
	 *            another point on the line
	 * @return A <code>Vec3</code> object which specifies the intersection
	 *         point of line and the plane, or null if the line and the plane do
	 *         not intersect.
	 */
	public Vec3 intersects(Vec3 p0, Vec3 p1) {
		Vec3 p = p1.minus(p0);
		if (p.dot(_n) == 0) {
			return null;
		}
		double t = (_d - p0.dot(_n)) / p.dot(_n);

		/* p0 + t * (p1-p0) */
		Vec3 intersect = p0.plus(p.times(t));

		return intersect;
	}

	/**
	 * Computes the distance from a point to this plane.
	 * 
	 * @param p
	 *            The point
	 * @return The distance from the given point to the plane.
	 */
	public double distance(Vec3 p) {
		try {
			return _n.dot(_a.minus(p));
		} catch (RuntimeException e) {
			System.err.println("Normal: " + _n);
			System.err.println("A     : " + _a);
			System.err.println("P     : " + p);
			System.err.println("A-P   : " + _a.minus(p));
			throw e;
		}
	}

	/**
	 * Returns the line where two planes intersect. The line where two planes
	 * intersect is given by the cross product of the normals of both planes.
	 * The equation of the line is given in the form of a Vec3 object.
	 * 
	 * @param p
	 *            The plane to intersect
	 * @return a Vec3 object which represents the line.
	 */
	public Vec3 cross(Plane p) {
		return this._n.cross(p._n);
	}
}
